# -*- coding: utf-8 -*-
"""
乒乓球培训管理系统 - 预约模型
管理课程预约的完整生命周期
"""

from datetime import datetime, date, time, timedelta
from decimal import Decimal
from flask_sqlalchemy import SQLAlchemy

from app import db


class Reservation(db.Model):
    """
    预约模型
    管理学员和教练的课程预约
    """
    __tablename__ = 'reservations'

    # 基础字段
    id = db.Column(db.BigInteger, primary_key=True, autoincrement=True)
    campus_id = db.Column(db.BigInteger, db.ForeignKey('campuses.id'),
                         nullable=False, comment='校区ID')
    student_id = db.Column(db.BigInteger, db.ForeignKey('users.id'),
                          nullable=False, comment='学员ID')
    coach_id = db.Column(db.BigInteger, db.ForeignKey('users.id'),
                        nullable=False, comment='教练ID')
    table_id = db.Column(db.BigInteger, db.ForeignKey('tables.id'),
                        nullable=False, comment='球台ID')

    # 时间信息
    reservation_date = db.Column(db.Date, nullable=False, comment='预约日期')
    start_time = db.Column(db.Time, nullable=False, comment='开始时间')
    end_time = db.Column(db.Time, nullable=False, comment='结束时间')
    duration_minutes = db.Column(db.Integer, nullable=False, default=60, comment='时长（分钟）')

    # 状态和费用
    status = db.Column(db.Enum('pending', 'confirmed', 'cancelled', 'completed', 'no_show'),
                      nullable=False, default='pending', comment='预约状态')
    price = db.Column(db.Numeric(8, 2), nullable=False, comment='课程费用')

    # 取消信息
    cancel_reason = db.Column(db.String(255), nullable=True, comment='取消原因')
    cancelled_at = db.Column(db.DateTime, nullable=True, comment='取消时间')
    cancelled_by = db.Column(db.BigInteger, db.ForeignKey('users.id'),
                           nullable=True, comment='取消人')

    # 审计字段
    created_at = db.Column(db.DateTime, nullable=False, default=datetime.now, comment='创建时间')
    updated_at = db.Column(db.DateTime, nullable=False, default=datetime.now,
                          onupdate=datetime.now, comment='更新时间')

    # 关联关系
    student = db.relationship('User', foreign_keys=[student_id],
                             backref=db.backref('student_reservations', lazy='dynamic'))
    coach = db.relationship('User', foreign_keys=[coach_id],
                           backref=db.backref('coach_reservations', lazy='dynamic'))
    cancelled_by_user = db.relationship('User', foreign_keys=[cancelled_by])
    campus = db.relationship('Campus', backref=db.backref('reservations', lazy='dynamic'))
    table = db.relationship('Table')
    evaluation = db.relationship('Evaluation', backref='reservation', uselist=False, lazy=True)

    def __init__(self, **kwargs):
        super(Reservation, self).__init__(**kwargs)
        # 自动计算时长
        if self.start_time and self.end_time:
            self.calculate_duration()

    def calculate_duration(self):
        """计算时长"""
        start_dt = datetime.combine(date.today(), self.start_time)
        end_dt = datetime.combine(date.today(), self.end_time)
        self.duration_minutes = int((end_dt - start_dt).seconds / 60)

    def get_datetime_start(self):
        """获取开始日期时间"""
        return datetime.combine(self.reservation_date, self.start_time)

    def get_datetime_end(self):
        """获取结束日期时间"""
        return datetime.combine(self.reservation_date, self.end_time)

    def is_pending(self):
        """是否待确认"""
        return self.status == 'pending'

    def is_confirmed(self):
        """是否已确认"""
        return self.status == 'confirmed'

    def is_cancelled(self):
        """是否已取消"""
        return self.status == 'cancelled'

    def is_completed(self):
        """是否已完成"""
        return self.status == 'completed'

    def is_no_show(self):
        """是否未出席"""
        return self.status == 'no_show'

    def can_be_cancelled(self):
        """是否可以取消"""
        if self.status not in ['pending', 'confirmed']:
            return False

        # 检查24小时限制
        from app.config import Config
        now = datetime.now()
        start_datetime = self.get_datetime_start()
        hours_diff = (start_datetime - now).total_seconds() / 3600

        return hours_diff >= Config.CANCEL_HOURS_LIMIT

    def can_be_confirmed(self):
        """是否可以确认"""
        return self.status == 'pending'

    def can_be_completed(self):
        """是否可以标记完成"""
        return self.status == 'confirmed' and self.get_datetime_end() <= datetime.now()

    def confirm(self):
        """确认预约"""
        if self.can_be_confirmed():
            self.status = 'confirmed'
            return True
        return False

    def cancel(self, cancelled_by_id, reason=None):
        """取消预约"""
        if self.can_be_cancelled():
            self.status = 'cancelled'
            self.cancelled_by = cancelled_by_id
            self.cancelled_at = datetime.now()
            self.cancel_reason = reason
            return True
        return False

    def complete(self):
        """完成课程"""
        if self.can_be_completed():
            self.status = 'completed'
            return True
        return False

    def mark_no_show(self):
        """标记未出席"""
        if self.status == 'confirmed':
            self.status = 'no_show'
            return True
        return False

    def get_status_display(self):
        """获取状态显示文本"""
        if self.status == 'cancelled':
            # 通过cancel_reason判断是教练拒绝还是普通取消
            if self.cancel_reason and self.cancel_reason.startswith('教练拒绝'):
                return '教练拒绝'
            else:
                return '已取消'

        status_map = {
            'pending': '待确认',
            'confirmed': '已确认',
            'completed': '已完成',
            'no_show': '未出席'
        }
        return status_map.get(self.status, self.status)

    def get_duration_hours(self):
        """获取时长（小时）"""
        return self.duration_minutes / 60

    def get_price_yuan(self):
        """获取价格（元）"""
        return float(self.price) if self.price else 0

    def is_today(self):
        """是否是今天的预约"""
        return self.reservation_date == date.today()

    def is_past(self):
        """是否是过去的预约"""
        return self.get_datetime_end() < datetime.now()

    def is_upcoming(self):
        """是否是即将到来的预约"""
        now = datetime.now()
        start_time = self.get_datetime_start()
        return start_time > now and (start_time - now).total_seconds() <= 3600  # 1小时内

    @staticmethod
    def check_time_conflict(table_id, reservation_date, start_time, end_time, exclude_id=None):
        """检查时间冲突"""
        query = Reservation.query.filter(
            Reservation.table_id == table_id,
            Reservation.reservation_date == reservation_date,
            Reservation.status.in_(['pending', 'confirmed']),
            db.or_(
                db.and_(Reservation.start_time < end_time,
                       Reservation.end_time > start_time)
            )
        )

        if exclude_id:
            query = query.filter(Reservation.id != exclude_id)

        return query.first() is not None

    @staticmethod
    def get_user_monthly_cancellations(user_id, year_month):
        """获取用户当月取消次数"""
        start_date = datetime.strptime(f'{year_month}-01', '%Y-%m-%d').date()
        if start_date.month == 12:
            end_date = date(start_date.year + 1, 1, 1)
        else:
            end_date = date(start_date.year, start_date.month + 1, 1)

        return Reservation.query.filter(
            db.or_(Reservation.student_id == user_id, Reservation.coach_id == user_id),
            Reservation.status == 'cancelled',
            Reservation.cancelled_by == user_id,
            Reservation.reservation_date >= start_date,
            Reservation.reservation_date < end_date
        ).count()

    def to_dict(self):
        """转换为字典格式"""
        return {
            'id': self.id,
            'campus_id': self.campus_id,
            'student_id': self.student_id,
            'coach_id': self.coach_id,
            'table_id': self.table_id,
            'reservation_date': self.reservation_date.isoformat() if self.reservation_date else None,
            'start_time': self.start_time.strftime('%H:%M:%S') if self.start_time else None,
            'end_time': self.end_time.strftime('%H:%M:%S') if self.end_time else None,
            'duration_minutes': self.duration_minutes,
            'status': self.status,
            'status_display': self.get_status_display(),
            'price': float(self.price) if self.price else None,
            'cancel_reason': self.cancel_reason,
            'cancelled_at': self.cancelled_at.isoformat() if self.cancelled_at else None,
            'created_at': self.created_at.isoformat() if self.created_at else None,
            'student_name': self.student.real_name if self.student else None,
            'coach_name': self.coach.real_name if self.coach else None,
            'table_name': self.table.name if self.table else None,
            'can_be_cancelled': self.can_be_cancelled(),
            'can_be_confirmed': self.can_be_confirmed(),
            'is_upcoming': self.is_upcoming()
        }

    def __repr__(self):
        return f'<Reservation {self.student.real_name if self.student else "Unknown"} -> {self.coach.real_name if self.coach else "Unknown"} on {self.reservation_date} ({self.status})>'